package remote

import (
	"deploy-tools/model"
	"fmt"
	"golang.org/x/crypto/ssh"
	"math"
	"net"
	"sync"
	"time"
)

// Client 远程
type Client struct {
	*model.Host
	client     *ssh.Client
	LastResult string
	sync       *sync.Mutex
	Timeout    int
}

func NewRemote(host *model.Host) *Client {
	return &Client{
		Host: host,
		sync: &sync.Mutex{},
	}
}

// Connect 连接，timeout 秒，超时时长，-1表示不限制
func (n *Client) Connect(timeout int) error {
	if n.client != nil {
		return nil
	}
	if timeout == -1 {
		timeout = math.MaxInt
	}
	n.Timeout = timeout
	sshConfig := ssh.ClientConfig{}
	sshConfig.SetDefaults()
	sshConfig.User = n.User
	sshConfig.Auth = []ssh.AuthMethod{
		ssh.Password(n.Password),
	}
	sshConfig.HostKeyCallback = func(hostname string, remote net.Addr, key ssh.PublicKey) error {
		return nil
	}
	sshConfig.Timeout = time.Second * time.Duration(timeout)
	addr := fmt.Sprintf("%s:%d", n.Host.Host, n.Port)
	client, err := ssh.Dial("tcp", addr, &sshConfig)
	if err != nil {
		fmt.Printf("connect error: %v\n", err)
		return err
	}
	n.client = client
	go n.onDisConnect()
	return nil
}

func (n *Client) Client() (*ssh.Client, error) {
	if n.client != nil {
		return n.client, nil
	}
	n.sync.Lock()
	defer n.sync.Unlock()
	err := n.Connect(n.Timeout)
	if err != nil {
		return nil, err
	}
	return n.client, nil
}

func (n *Client) Close() {
	if n.client != nil {
		n.client.Close()
		n.client = nil
	}
}

func (n *Client) onDisConnect() {
	if n.client != nil {
		err := n.client.Wait()
		fmt.Printf("disconnect: %v\n", err)
	}
	n.client = nil
}

func (n *Client) getSSHConfig() ssh.ClientConfig {
	config := ssh.ClientConfig{}
	config.SetDefaults()
	config.User = n.User
	config.Auth = []ssh.AuthMethod{
		ssh.Password(n.Password),
	}
	config.HostKeyCallback = func(hostname string, remote net.Addr, key ssh.PublicKey) error {
		return nil
	}
	config.Timeout = time.Second * 60
	return config
}
